﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyClass_CRC
{
    class myclass_crc
    {
        public static UInt16 CRC16(byte[] p, int datalen)
        {
            byte CRC16Lo, CRC16Hi, CL, CH, SaveHi, SaveLo;
            int i, Flag;
            CRC16Lo = 0xFF;
            CRC16Hi = 0xFF;
            CL = 0x01;
            CH = 0xA0;
            for (i = 0; i < datalen; i++)
            {
                CRC16Lo ^= p[ i ];                                            //每一个数据与CRC寄存器进行异或
                for (Flag = 0; Flag < 8; Flag++)
                {
                    SaveHi = CRC16Hi;
                    SaveLo = CRC16Lo;
                    CRC16Hi >>= 1;
                    CRC16Lo >>= 1;                                  //高位右移一位，低位右移一位
                    if ((SaveHi & 0x01) == 0x01)        //如果高位字节最后一位为1
                        CRC16Lo |= 0x80;                        //则低位字节右移后前面补1否则自动补0
                    if ((SaveLo & 0x01) == 0x01)            //如果LSB为1，则与多项式码进行异或
                    {
                        CRC16Hi ^= CH;
                        CRC16Lo ^= CL;
                    }
                }
            }
            return (UInt16)((CRC16Hi << 8) | CRC16Lo);
        }

        private UInt16[] Crc16IbmTable = new UInt16[]
        {
          0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
          0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
        };

        /// <summary>
        /// Calulate CRC16(IBM) for byte stream, Poly = X^16 + X^15 + X^2 + 1(0x18005)
        /// </summary>
        /// <param name="data">array</param>
        /// <param name="offset"></param>
        /// <param name="len">length of array </param>
        /// <returns>checksum</returns>
        public UInt16 Crc16Ibm(byte[] data, int offset, int len)
        {
            UInt16 crc = 0;

            for (int i = offset; i < offset + len; i++)
            {
                crc = (UInt16)((crc << 4) ^ Crc16IbmTable[(crc >> 12) ^ ((data[i] >> 4) & 0x0f)]);
                crc = (UInt16)((crc << 4) ^ Crc16IbmTable[(crc >> 12) ^ (data[i] & 0x0f)]);
            }
            return crc;
        }

        public byte Crc8Value(byte[] p, UInt16 datalen)
        {
            byte CRC8, C8;
            int i, Flag;
            CRC8 = 00;        //初始值
            C8 = 0x8C;        //多项式
            for (i = 0; i < datalen; i++)
            {
                CRC8 ^= p[ i ];                                           //每一个数据与CRC寄存器进行异或
                for (Flag = 0; Flag < 8; Flag++)
                {
                    if ((CRC8 & 0x01) != 0)
                    {
                        CRC8 = (byte)((CRC8 >> 1) ^ C8);
                    }
                    else
                    {
                        CRC8 >>= 1;
                    }
                }
            }
            return CRC8;
        }
    }
}
